using System.Reflection;
using Microsoft.Extensions.Logging;
using SeataNet.Core.Attributes;
using SeataNet.Core.Common;
using SeataNet.Core.Configuration;
using SeataNet.Core.Context;
using SeataNet.Core.Exceptions;
using SeataNet.Core.Model;
using SeataNet.Core.Transaction;

namespace SeataNet.Core.Interceptors
{
    /// <summary>
    /// 全局事务拦截器
    /// </summary>
    public class GlobalTransactionInterceptor
    {
        private readonly ITransactionManager _transactionManager;
        private readonly ILogger<GlobalTransactionInterceptor> _logger;
        
        public GlobalTransactionInterceptor(ITransactionManager transactionManager, ILogger<GlobalTransactionInterceptor> logger)
        {
            _transactionManager = transactionManager ?? throw new ArgumentNullException(nameof(transactionManager));
            _logger = logger ?? throw new ArgumentNullException(nameof(logger));
        }
        
        /// <summary>
        /// 拦截方法执行
        /// </summary>
        /// <param name="target">目标对象</param>
        /// <param name="method">目标方法</param>
        /// <param name="arguments">方法参数</param>
        /// <param name="attribute">全局事务特性</param>
        /// <param name="next">下一个委托</param>
        /// <returns>方法执行结果</returns>
        public async Task<object?> InterceptAsync(object target, MethodInfo method, object?[] arguments, 
            GlobalTransactionalAttribute attribute, Func<object?, object?[]?, Task<object?>> next)
        {
            if (attribute == null)
            {
                return await next(target, arguments);
            }
            
            // 获取配置信息
            var configuration = SeataConfiguration.Instance;
            var applicationId = configuration.ApplicationId;
            var transactionServiceGroup = configuration.TransactionServiceGroup;
            
            // 检查是否已在全局事务中
            var existingXid = RootContext.Xid;
            var isExistingTransaction = !string.IsNullOrEmpty(existingXid);
            
            // 处理事务传播行为
            switch (attribute.Propagation)
            {
                case TransactionPropagationBehavior.Required:
                    if (isExistingTransaction)
                    {
                        return await next(target, arguments);
                    }
                    break;
                    
                case TransactionPropagationBehavior.Supports:
                    if (!isExistingTransaction)
                    {
                        return await next(target, arguments);
                    }
                    break;
                    
                case TransactionPropagationBehavior.Mandatory:
                    if (!isExistingTransaction)
                    {
                        throw new TransactionException("No existing transaction found for MANDATORY propagation");
                    }
                    return await next(target, arguments);
                    
                case TransactionPropagationBehavior.RequiresNew:
                    if (isExistingTransaction)
                    {
                        // 挂起当前事务
                        RootContext.Unbind();
                    }
                    break;
                    
                case TransactionPropagationBehavior.NotSupported:
                    if (isExistingTransaction)
                    {
                        // 挂起当前事务
                        RootContext.Unbind();
                        try
                        {
                            return await next(target, arguments);
                        }
                        finally
                        {
                            // 恢复当前事务
                            RootContext.Bind(existingXid);
                        }
                    }
                    break;
                    
                case TransactionPropagationBehavior.Never:
                    if (isExistingTransaction)
                    {
                        throw new TransactionException("Existing transaction found for NEVER propagation");
                    }
                    break;
                    
                case TransactionPropagationBehavior.Nested:
                    // 嵌套事务暂不实现
                    if (!isExistingTransaction)
                    {
                        break;
                    }
                    return await next(target, arguments);
            }
            
            // 开始新事务
            var transactionName = attribute.Name ?? $"{target.GetType().Name}.{method.Name}";
            var timeout = attribute.Timeout > 0 ? attribute.Timeout : TransactionConstants.DEFAULT_GLOBAL_TIMEOUT;

            string xid;
            try
            {
                xid = await _transactionManager.BeginAsync(timeout, transactionName);
            }
            catch (Exception ex)
            {
                _logger.LogError(ex, "Failed to begin transaction [{transactionName}]", transactionName);
                throw new TransactionException($"Failed to begin transaction {transactionName}", ex);
            }

            // 创建事务上下文
            var context = new GlobalTransactionContext
            {
                Xid = xid,
                TransactionName = transactionName,
                Status = (int)TransactionStatus.Begin
            };

            // 绑定到当前上下文
            RootContext.Bind(xid);

            try
            {
                // 执行目标方法
                var result = await next(target, arguments);
                
                // 提交事务
                try
                {
                    await _transactionManager.CommitAsync(context.Xid);
                }
                catch (Exception ex)
                {
                    _logger.LogError(ex, "Failed to commit transaction [{xid}]", context.Xid);
                    throw new TransactionExecutionException($"Failed to commit transaction {context.Xid}", ex);
                }
                
                return result;
            }
            catch (Exception ex)
            {
                // 检查是否需要回滚
                var shouldRollback = ShouldRollback(ex, attribute);
                
                if (shouldRollback)
                {
                    // 回滚事务
                    try
                    {
                        await _transactionManager.RollbackAsync(context.Xid);
                    }
                    catch (Exception rollbackEx)
                    {
                        _logger.LogError(rollbackEx, "Failed to rollback transaction [{xid}]", context.Xid);
                        throw new TransactionExecutionException($"Failed to rollback transaction {context.Xid}", rollbackEx);
                    }
                    
                    _logger.LogWarning(ex, "Transaction [{xid}] has been rollback due to exception", context.Xid);
                }
                else
                {
                    // 不回滚，尝试提交
                    try
                    {
                        await _transactionManager.CommitAsync(context.Xid);
                    }
                    catch (Exception commitEx)
                    {
                        _logger.LogError(commitEx, "Failed to commit transaction [{xid}]", context.Xid);
                        throw new TransactionExecutionException($"Failed to commit transaction {context.Xid}", commitEx);
                    }
                }
                
                throw;
            }
            finally
            {
                // 清理上下文
                RootContext.Unbind();
                
                // 恢复原有事务（如果存在）
                if (attribute.Propagation == TransactionPropagationBehavior.RequiresNew && isExistingTransaction)
                {
                    RootContext.Bind(existingXid);
                }
            }
        }
        
        /// <summary>
        /// 判断是否需要回滚
        /// </summary>
        /// <param name="exception">异常</param>
        /// <param name="attribute">全局事务特性</param>
        /// <returns>是否需要回滚</returns>
        private bool ShouldRollback(Exception exception, GlobalTransactionalAttribute attribute)
        {
            if (attribute.RollbackFor != null && attribute.RollbackFor.Length > 0)
            {
                return attribute.RollbackFor.Any(rollbackType => rollbackType.IsInstanceOfType(exception));
            }
            
            if (attribute.NoRollbackFor != null && attribute.NoRollbackFor.Length > 0)
            {
                return !attribute.NoRollbackFor.Any(noRollbackType => noRollbackType.IsInstanceOfType(exception));
            }
            
            // 默认回滚所有异常
            return true;
        }
    }
}